package fr.unice.polytech.chord.gui.dialogs;

import java.awt.BorderLayout;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

import fr.unice.polytech.chord.core.ChordNode;
import fr.unice.polytech.chord.core.Entries;
import fr.unice.polytech.chord.core.Entry;
import fr.unice.polytech.chord.core.Key;
import fr.unice.polytech.chord.core.Tracker;

/**
 * Dialogs used in order to show {@link Entries} on the overlay or on a specific
 * {@link ChordNode}.
 * 
 * @author Anthony Parisy
 * @author Laurent Pellegrino
 * @author Marc Valdener
 * 
 * @version 06/11/2009
 */
@SuppressWarnings("serial")
public class ShowEntriesDialog extends ToolBarJDialog {

	private enum Type {
		ALL, NODE
	};

	private ChordNode node;

	private Tracker tracker;

	private boolean refreshing;

	private Type type = Type.ALL;

	private DefaultTableModel tableModel;

	public ShowEntriesDialog(JFrame parent, JButton toolBarButton) {
		super(parent, "Show Entries (0)", toolBarButton);
	}

	public ShowEntriesDialog(JFrame parent, JButton toolBarButton,
			Tracker tracker) {
		this(parent, toolBarButton);
		this.tracker = tracker;
	}

	public ShowEntriesDialog(JFrame parent, ChordNode node, String title) {
		super(parent, title, null);
		this.node = node;
		this.type = Type.NODE;
	}

	public void createAndShowDialog() {
		super.getContentPane().add(this.createDialog());

		final Runnable refreshThread = new Runnable() {
			@Override
			public void run() {
				ShowEntriesDialog.this.refreshing = true;
				while (ShowEntriesDialog.this.refreshing) {
					ShowEntriesDialog.this.retrieveEntries();
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		};

		super.addComponentListener(new ComponentListener() {

			@Override
			public void componentShown(ComponentEvent e) {
				new Thread(refreshThread).start();
			}

			@Override
			public void componentResized(ComponentEvent e) {
			}

			@Override
			public void componentMoved(ComponentEvent e) {
			}

			@Override
			public void componentHidden(ComponentEvent e) {

			}
		});

		super.addWindowListener(new WindowAdapter() {

			@Override
			public void windowClosing(WindowEvent e) {
				super.windowClosing(e);
				ShowEntriesDialog.this.refreshing = false;
			}
		});

		super.setSize(400, 200);
		super.setResizable(false);
		super.setLocationRelativeTo(super.getOwner());
		super.setVisible(true);

	}

	private JPanel createDialog() {
		JPanel container = new JPanel(new BorderLayout());
		container.setSize(400, 200);

		Object data[][] = new Object[Key.NB_BITS][2];
		String columnNames[];

		if (this.type == Type.NODE) {
			columnNames = new String[] { "Key", "Value" };
		} else {
			columnNames = new String[] { "Key", "Node", "Value" };
		}

		this.tableModel = new DefaultTableModel(data, columnNames) {
			@Override
			public boolean isCellEditable(int row, int column) {
				return false;
			}
		};
		this.tableModel.setNumRows(0);

		JTable entriesTable = new JTable(this.tableModel);
		entriesTable.setFillsViewportHeight(true);
		entriesTable.getColumn("Key").setMinWidth(40);
		if (this.type == Type.ALL) {
			entriesTable.getColumn("Node").setMinWidth(40);
		}
		entriesTable.getColumn("Value").setMinWidth(290);
		entriesTable.setRowHeight(20);
		entriesTable.setAutoCreateRowSorter(true);

		JScrollPane scrollPane = new JScrollPane(entriesTable);

		container.add(entriesTable.getTableHeader(), BorderLayout.NORTH);
		container.add(scrollPane, BorderLayout.CENTER);

		return container;
	}

	public void addRows(Key key, Entries<String> entries) {
		for (Entry<String> entry : entries) {
			if (this.type == Type.NODE) {
				this.tableModel.addRow(new Object[] {
						entry.getKey().getValue(), entry });
			} else {
				this.tableModel.addRow(new Object[] {
						entry.getKey().getValue(), key, entry });
			}
		}
	}

	public void clearTable() {
		this.tableModel.getDataVector().removeAllElements();
	}

	private void retrieveEntries() {
		try {
			this.clearTable();
			this.tableModel.fireTableDataChanged();

			if (this.type == Type.NODE) {
				this.addRows(this.node.getKey(), this.node.getEntries());
			} else {
				if (this.tracker.getNumberOfPeersManaged() != 0) {
					this.node = this.tracker.getRandomPeer();
					ChordNode currentNode = this.node;
					this
							.addRows(currentNode.getKey(), currentNode
									.getEntries());

					while (!(currentNode = currentNode.getSuccessor()).getKey()
							.equals(this.node.getKey())) {
						this.addRows(currentNode.getKey(), currentNode
								.getEntries());
					}
				}
				super.setTitle("Show Entries (" + this.tableModel.getRowCount()
						+ ")");
			}
		} catch (Exception e) {
			// do nothing, wait for stabilization...
		}
	}
}
